package com.translate.web.api.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.translate.web.param.IdAndUserIdParam;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import com.translate.vo.PayManagerVO;
import com.translate.vo.ServiceTypeVO;
import com.translate.vo.UserVO;
import com.translate.vo.contract.IPayManagerVO;
import com.translate.vo.contract.IUserVO;
import com.response.vo.ResponseModel;
import com.controller.base.AbstractCommonController;
import com.page.PageResponseData;
import com.param.impl.IdParam;
import com.payment.Context;
import com.payment.IPaymentBehavior;
import com.payment.factory.PayFactory;
import com.translate.web.param.PayManagerUpdateParam;
import com.translate.web.constant.RedisConstant;
import com.translate.web.param.PayBehaviorRequestParam;
import com.translate.web.param.PayManagerSearchParam;
import com.translate.web.param.contract.IPayManagerAddParam;
import com.translate.entity.Order;
import com.translate.entity.OrderLog;
import com.translate.entity.PayManager;
import com.translate.entity.PayType;
import com.translate.entity.User;
import com.translate.web.service.IChangeRecordService;
import com.translate.web.service.ICommissionManagementDetailService;
import com.translate.web.service.ICommissionManagementService;
import com.translate.web.service.INoticeCenterService;
import com.translate.web.service.INvitationRewardsConfService;
import com.translate.web.service.IOrderLogService;
import com.translate.web.service.IOrderService;
import com.translate.web.service.IPayManagerService;
import com.translate.web.service.IPayTypeService;
import com.translate.web.service.IServicePriceConfService;
import com.translate.web.service.IServiceTypeService;
import com.translate.web.service.ITeamService;
import com.translate.web.service.IUserService;
import com.basic.service.contract.IBaseService;
import com.common.util.ListConvertMap;
import com.common.util.MergeDataSource;

/**
 * 支付管理
 */
@RestController
@RequestMapping("payManager")
public class PayManagerController extends AbstractCommonController<PayManager, PayManagerSearchParam> {

	private IPayManagerService service;

	IOrderService orderService;

	IServiceTypeService serviceTypeService;

	IPayTypeService payTypeService;

	IUserService userService;

	IOrderLogService orderLogService;

	INoticeCenterService centerService;

	IChangeRecordService changeRecordService;

	IServicePriceConfService priceConfService;
	
	INvitationRewardsConfService vitationRewardsConfService;
	
	ICommissionManagementService commissionManagementService;
	
	ITeamService teamService;
	
	ICommissionManagementDetailService 	commissionManagementDetailService;
	
	@Resource
	public void setTeamService(ITeamService teamService) {
		this.teamService = teamService;
	}

	@Resource
    public void setServiceTypeService(IServiceTypeService serviceTypeService) {
        this.serviceTypeService = serviceTypeService;
    }
	
	@Resource
    public void setCommissionManagementService(ICommissionManagementService commissionManagementService) {
        this.commissionManagementService = commissionManagementService;
    }
	
	
	@Resource
	public void setVitationRewardsConfService(INvitationRewardsConfService vitationRewardsConfService) {
		this.vitationRewardsConfService = vitationRewardsConfService;
	}

	@Resource
	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	@Resource
	public void setCenterService(INoticeCenterService centerService) {
		this.centerService = centerService;
	}

	@Resource
	public void setOrderLogService(IOrderLogService orderLogService) {
		this.orderLogService = orderLogService;
	}

	@Resource
	public void setChangeRecordService(IChangeRecordService changeRecordService) {
		this.changeRecordService = changeRecordService;
	}

	@Resource
	public void setPriceConfService(IServicePriceConfService priceConfService) {
		this.priceConfService = priceConfService;
	}

	@Resource
	public void setService(IPayManagerService service) {
		this.service = service;
	}

	@Resource
	public void setPayTypeService(IPayTypeService payTypeService) {
		this.payTypeService = payTypeService;
	}

	@Resource
	public void setTypeService(IServiceTypeService serviceTypeService) {
		this.serviceTypeService = serviceTypeService;
	}

	@Resource
	public void setOrderService(IOrderService orderService) {
		this.orderService = orderService;
	}

	public PayManagerController(IPayManagerService service) {
		this.service = service;
	}

	protected long setCreateInfo(IPayManagerAddParam param, HttpServletRequest httpServletRequest) {
		long userId = (long) httpServletRequest.getAttribute("userId");
		param.setUserId((int) userId);
		return userId;
	}

	protected void frontProcesserVO(PayManagerSearchParam param, NativeWebRequest object) {

		// 查询最大的id

		super.frontProcesserVO(param, object);

		long userId = (long) object.getAttribute("userId", RequestAttributes.SCOPE_REQUEST);

		User userInfoToCache = userService.getUserInfoToCache((int) userId);

		Integer teamId = userInfoToCache.getTeamId();
		
		if (1 != userInfoToCache.getStatus()) { // 未审核 或 未通过
			teamId = 0;
		}
		

		List<Integer> userIds = new ArrayList<Integer>();
		
		Integer userIdByParam = param.getUserId();
		
		if (null != userIdByParam) {
			userIds.add(userIdByParam);
		}
		
		if (0 != teamId) {
			// 团队搜索
			param.setTeamId(teamId);

			String userName = param.getUserName();

			if (null != userName) {

				// 团队搜索
				List<User> userIdsBySearchName = userService.getUserIdsBySearchName(userName);

				if (null != userIdsBySearchName && userIdsBySearchName.size() > 0) {
					
					param.setUserFound(0);
					
					List<Integer> collect = userIdsBySearchName.stream().map(e -> e.getId().intValue()).collect(Collectors.toList());
					
					userIds.addAll(collect);
				} 
			}

		} else {
			userIds.add((int) userId);
			
			param.setUserFound(0);
		}
		
		if (0 == userIds.size()) {
			return;
		}
		
		param.setUserIds(userIds);

	}

	@PostMapping("immediatePayment")
	@Transactional
	public ResponseModel<Integer> immediatePayment(
			@RequestBody @Validated PayBehaviorRequestParam payBehaviorRequestParam, NativeWebRequest object) {

		payBehaviorRequestParam.setUserId((int) this.getUserId(object));

		Integer payType = payBehaviorRequestParam.getPayType();

		PayType valueFromHash = this.payTypeService.getValueFromHash(RedisConstant.PAY_TYPE, payType.toString());

		IPaymentBehavior operationClass = PayFactory.getOperationClass((int) valueFromHash.getIsSpecial().intValue(),
				new IBaseService[] { service, userService, orderService, orderLogService, changeRecordService,
						centerService, serviceTypeService,vitationRewardsConfService, commissionManagementService,
						commissionManagementDetailService,teamService

				});

		Context context = new Context(operationClass);

		return ResponseModel.success(context.run(payBehaviorRequestParam));

	}

	/**
	 * 取消订单
	 * 
	 * @return
	 */
	@PostMapping("cancelOrder")
	@Transactional
	public ResponseModel<Integer> cancelOrder(@RequestBody @Validated IdParam param,
			HttpServletRequest httpServletRequest) {

		long userId = (long) httpServletRequest.getAttribute("userId");

		User userDetails = userService.getUserInfoToCache((int)userId);
		
		// 验证 是团长吧
		Byte isRegimental = userDetails.getIsRegimental();
		
		long assocId = getAssocIds[isRegimental].apply(userDetails);
		IdAndUserIdParam param1 = new IdAndUserIdParam();
		param1.setId(param.getId());
		param1.setUserId(userId);
		cacelOrders[isRegimental].apply(param1, assocId);
		
		return ResponseModel.<Integer>success(1);
	}

	protected void cancelByPerson(IdAndUserIdParam param, long userId) {

		Integer id = param.getId();
		
		// 添加日志
		
		List<Order> ordersByPayManagerIdAndUserId = orderService.getOrdersByPayManagerIdAndUserId(id, (int)userId);
		
		this.service.cancelOrder(id, (int) userId);

		this.orderService.cancelOrder(id, (int) userId);

		//个人取消订单判断下是否有查重券，有的话返回给个人
		List<Order> orders = this.service.getOrdersByPayManagerIdAndPayType(id,(int) userId);
		if(orders.size() > 0){
			this.service.cancelTicket((int) userId);
		}

		insertCancelOrderLogs(ordersByPayManagerIdAndUserId, id);
	}

	protected void insertCancelOrderLogs(List<Order> ordersByPayManagerIdAndUserId, int payManagerId) {
		
		
		int size = ordersByPayManagerIdAndUserId.size();
		
		if (0 == size) {
			return;
		}
		OrderLog[] orderLogs = new OrderLog[size];
		
		OrderLog orderLog;
		
		byte cancelOrder = -1;
		
		long timeMillis = System.currentTimeMillis() / 1000;
		
		int i  = 0;
		for (Order order : ordersByPayManagerIdAndUserId) {
		
			orderLog = new OrderLog();
			
			orderLog.setOrderId(order.getId());
			orderLog.setPayManagerId(payManagerId);
			orderLog.setOrderStatus(cancelOrder);
			
			orderLog.setUserId(order.getUserId());
			
			orderLog.setType((byte) 2);
			
			orderLog.setCreateTime(timeMillis);
			
			orderLogs[i] = orderLog;
			
			i++;
		}
		
		orderLogService.batchInsert(orderLogs);
	}
	
	
	protected void cancelByTeam(IdAndUserIdParam param, long teamId) {

		Integer id = param.getId();
		
		List<Order> ordersByPayManagerIdAndUserId = orderService.getOrdersByPayManagerIdAndTeamId(id, (int)teamId);

		this.service.cancelOrderByTeam(id, (int) teamId);

		this.orderService.cancelOrderByTeam(id, (int) teamId);

		//团队取消订单判断下是否有查重券，有的话返回给团长
		List<Order> orders = this.service.getOrdersByPayManagerIdAndPayType(id,(int)param.getUserId());
		if(orders.size() > 0){
			this.service.cancelTicket((int)param.getUserId());
		}
		// 添加日志
		insertCancelOrderLogs(ordersByPayManagerIdAndUserId, id);
		
	}
	
	
	FunctionCacelOrder[] cacelOrders = new FunctionCacelOrder[] {
			(IdAndUserIdParam param, long userId) -> cancelByPerson(param, userId),
			(IdAndUserIdParam param, long userId) -> cancelByTeam(param, userId),
	};
	
	FunctionGetAssocId[] getAssocIds = new FunctionGetAssocId[] {
			(User userDetails) -> userDetails.getId(),
			(User userDetails) -> userDetails.getTeamId(),
	};
	
	
	
	private interface FunctionGetAssocId {
		
        long apply(User userDetails);
	}
	
	
	
	
	private interface FunctionCacelOrder {
		
        void apply(IdAndUserIdParam param, long userId);
	}
	
	
	

	@Override
	protected <VO> PageResponseData<VO> afterProcesserVO(PageResponseData<VO> orderList,
			PayManagerSearchParam payManagerSearchParam) {

		if (-1 == payManagerSearchParam.getUserFound()) {
			return new PageResponseData<VO>();
		}
		
		List<VO> data = orderList.getData();

		MergeDataSource<VO> mergeDataSource = new MergeDataSource<VO>(data);

		Function<VO, Integer> fUserId = (e) -> ((IPayManagerVO) e).getUserId();

		List<User> user = userService.getDataByIds(data, fUserId, new String[] { "id", "realname" });

		Map<Integer, User> listToMap = ListConvertMap.listToMap(user, e -> e.getId().intValue());

		mergeDataSource.mergeRelease(fUserId, listToMap, (VO vo, User u) -> {

			IPayManagerVO payManagerVO = (IPayManagerVO) vo;

			payManagerVO.setRealname(u.getRealname());

			return vo;
		});

		return orderList;
	}

	@Override
	protected IBaseService<PayManager> getBaseService() {
		return this.service;
	}

	/**
	 * 添加
	 * 
	 * @param <V>
	 * @param param
	 * @return
	 */
	@PostMapping("/update")
	public ResponseModel<Integer> update(@Validated @RequestBody PayManagerUpdateParam param,
			HttpServletRequest httpServletRequest) {
		int res = this.service.parseUpdate(param, PayManager.class);
		return ResponseModel.<Integer>success(res);
	}

	protected <VO> Class<VO> getTarget() {
		return (Class<VO>) PayManagerVO.class;
	}
}